﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System.Text;
using UnityEngine;
using System;
using System.Security.Cryptography;
public class IO{


    private static int AESKeyLength = 32;//AES加密的密码为32位
    private static char AESFillChar = 'Y';//AES密码填充字符

    public static string DefaultPassword = "yuzhengyang";//默认密码


    /// <summary>
    /// 复制文件到指定文件夹
    /// </summary>
    /// <param name="sourcePath"></param>
    /// <param name="targetPath"></param>
    public static void CopyDirecory(string sourcePath,string targetPath)
    {
        //if(Directory.Exists(targetPath))
        //{
        //    return;
        //}
        if(!Directory.Exists(sourcePath))
        {
            Debug.LogError("sourcePath not exit: " + sourcePath);
            return;
        }

        string[] files = Directory.GetFiles(sourcePath);
        try
        {
            if(!Directory.Exists(targetPath))
            {
                Directory.CreateDirectory(targetPath);
            }
            foreach (string item in files)
            {
                string file = item.Replace("\\", "/");
                string fileName = file.Substring(sourcePath.Length, file.Length - sourcePath.Length);
                File.Copy(file, targetPath + fileName, true);
            }
        }
        catch(Exception e)
        {
            Debug.LogWarning(e);
        }
    }




    /// <summary>
    /// 拷贝oldlab的文件到newlab下面
    /// </summary>
    /// <param name="sourcePath">lab文件所在目录(@"~\labs\oldlab")</param>
    /// <param name="savePath">保存的目标目录(@"~\labs\newlab")</param>
    /// <returns>返回:true-拷贝成功;false:拷贝失败</returns>
    public static bool CopyOldLabFilesToNewLab(string sourcePath, string savePath)
    {
        if (!Directory.Exists(savePath))
        {
            Directory.CreateDirectory(savePath);
        }

        #region //拷贝labs文件夹到savePath下
        try
        {
            string[] labDirs = Directory.GetDirectories(sourcePath);//目录
            string[] labFiles = Directory.GetFiles(sourcePath);//文件
            //if (labFiles.Length > 0)
            //{
            //    for (int i = 0; i < labFiles.Length; i++)
            //    {
            //        if (Path.GetFileName(labFiles[i]) != ".lab")//排除.lab文件
            //        {
            //            File.Copy(sourcePath + "\\" + Path.GetFileName(labFiles[i]), savePath + "\\" + Path.GetFileName(labFiles[i]), true);
            //        }
            //    }
            //}

            if (labFiles.Length > 0)
            {
                foreach (string item in labFiles)
                {
                    string file = item.Replace("\\", "/");
                    string fileName = file.Substring(sourcePath.Length, file.Length - sourcePath.Length);
                    File.Copy(file, savePath + fileName, true);
                }
            }
           
            if (labDirs.Length > 0)
            {
                for (int j = 0; j < labDirs.Length; j++)
                {
                    Directory.GetDirectories(sourcePath + "\\" + Path.GetFileName(labDirs[j]));

                    //递归调用
                    CopyOldLabFilesToNewLab(sourcePath + "\\" + Path.GetFileName(labDirs[j]), savePath + "\\" + Path.GetFileName(labDirs[j]));
                }
            }
        }
        catch (Exception)
        {
            return false;
        }
        #endregion
        return true;
    }






    /// <summary>
    /// 拷贝文件到指点目录
    /// </summary>
    /// <param name="sourceFile"></param>
    /// <param name="targetFile"></param>
    /// <param name="isClear">是否删除源文件</param>
    public static void CopyFile(string sourceFile,string targetPath,bool isClear = false)
    {
        if (!File.Exists(sourceFile))
        {
            //Loger.Error("File is not exists:" + sourceFile);
            return;
        }
        if (!Directory.Exists(targetPath))
        {
            Directory.CreateDirectory(targetPath);
        }
        string[] strs = sourceFile.Split('/');
        string fileName = strs[strs.Length - 1];
        File.Copy(sourceFile, targetPath + fileName, true);
        if(isClear)
        {
            IO.DeleteFiles(sourceFile);
        }
    }

    /// <summary>
    /// 复制文件到指定文件夹
    /// </summary>
    /// <param name="sourcePath"></param>
    /// <param name="targetPath"></param>
    public static void CopyLuaDirecory(string sourcePath, string targetPath)
    {
        if (Directory.Exists(targetPath))
        {
            DeleteFiles(targetPath);
            Directory.CreateDirectory(targetPath);
        }
        if (!Directory.Exists(sourcePath))
        {
            Debug.LogError("sourcePath not exit: " + sourcePath);
            return;
        }

        string[] files = Directory.GetFiles(sourcePath);
        try
        {
            if (!Directory.Exists(targetPath))
            {
                Directory.CreateDirectory(targetPath);
            }
            foreach (string item in files)
            {
                string file = item.Replace("\\", "/");
                string fileName = file.Substring(sourcePath.Length, file.Length - sourcePath.Length);
                File.Copy(file, targetPath + fileName, true);
            }
        }
        catch (Exception e)
        {
            Debug.LogWarning(e);
        }
    }


    /// <summary>
    /// 复制文件到指定文件夹
    /// </summary>
    /// <param name="sourcePath"></param>
    /// <param name="targetPath"></param>
    public static void CopyLuaDirecory2(string sourcePath, string targetPath)
    {
        if (Directory.Exists(targetPath))
        {
            DeleteFiles(targetPath);
            Directory.CreateDirectory(targetPath);
        }
        if (!Directory.Exists(sourcePath))
        {
            Debug.LogError("sourcePath not exit: " + sourcePath);
            return;
        }

        string[] files = Directory.GetFiles(sourcePath);
        try
        {
            if (!Directory.Exists(targetPath))
            {
                Directory.CreateDirectory(targetPath);
            }
            foreach (string item in files)
            {
                if (Path.GetExtension(item) != ".meta")
                {
                    string file = item.Replace("\\", "/");
                    string fileName = file.Substring(sourcePath.Length, file.Length - sourcePath.Length);
                    File.Copy(file, targetPath + fileName, true);
                }
            }
        }
        catch (Exception e)
        {
            Debug.LogWarning(e);
        }
    }


    /// <summary>
    /// 删除指定目录
    /// </summary>
    /// <param name="sourcePath"></param>
    /// <returns></returns>
    public static bool DeleteDirectory(string sourcePath)
    {
        if (!Directory.Exists(sourcePath))
        {
            return true;
        }
        try
        {
            //Directory.Delete(sourcePath);
            //return true;
            string[] labDirs = Directory.GetDirectories(sourcePath);//目录
            string[] labFiles = Directory.GetFiles(sourcePath);//文件

            IO.DeleteFiles(sourcePath);
            if (labDirs.Length > 0)
            {
                for (int j = 0; j < labDirs.Length; j++)
                {
                    Directory.GetDirectories(sourcePath + "\\" + Path.GetFileName(labDirs[j]));

                    //递归调用
                    DeleteDirectory(sourcePath + "\\" + Path.GetFileName(labDirs[j]));
                }
            }


            //foreach (string d in Directory.GetFileSystemEntries(sourcePath))
            //{
            //    if (File.Exists(d))
            //    {
            //        FileInfo fi = new FileInfo(d);
            //        if (fi.Attributes.ToString().IndexOf("ReadOnly") != -1)
            //            fi.Attributes = FileAttributes.Normal;
            //        File.Delete(d);//直接删除其中的文件 
            //    }
            //    else
            //        DeleteDirectory(d);////递归删除子文件夹
            //    Directory.Delete(d);
            //}


        }
        catch (Exception)
        {
            return false;
        }
        return true;
    }



    /// <summary>
    /// 删除指定文件
    /// </summary>
    /// <param name="sourcePath"></param>
    /// <returns></returns>
    public static bool DeleteFiles(string sourcePath)
    {
        if(!Directory.Exists(sourcePath))
        {
            Debug.LogWarning("source is not exit..:" + sourcePath);
            return false;
        }
        DirectoryInfo dirInfo = new DirectoryInfo(sourcePath);
        FileInfo[] fileInfos =  dirInfo.GetFiles();
        try
        {
            foreach (var item in fileInfos)
            {
                File.Delete(item.FullName);
            }
            if(dirInfo.GetDirectories().Length != 0)
            {
                foreach (var item in dirInfo.GetDirectories())
                {
                    if (!item.ToString().Contains("$") && (!item.ToString().Contains("Boot")))
                    {
                        DeleteFiles(dirInfo.ToString() + "\\" + item.ToString());
                    }
                }
            }
            Directory.Delete(sourcePath);
            return true;
        }
        catch(Exception e)
        {
            Debug.LogWarning(e);
            return false;
        }
    }

    /// <summary>
    /// 返回指定目录的所有文件
    /// </summary>
    /// <param name="path"></param>
    /// <param name="recursive"></param>
    /// <returns></returns>
    public static string[] GetFiles(string path, bool recursive = true)
    {
        List<string> files = new List<string>();
        string[] dirArr = Directory.GetFiles(path, "*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
        foreach (var item in dirArr)
        {
            if (Path.GetExtension(item) != ".meta")
                files.Add(item.Replace("\\", "/"));
        }
        return files.ToArray();
    }


    public static Dictionary<string, string> GetFilesDic(string path, bool recursive = true)
    {
        Dictionary<string, string> fileDic = new Dictionary<string, string>();
        string[] dirArr = Directory.GetFiles(path, "*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
        foreach (var item in dirArr)
        {
            if (Path.GetExtension(item) != ".meta")
            {
                string str = item.Replace("\\", "/");
                str = str.Replace(Application.dataPath + "/", "Assets/");
                string key = str.Replace("Assets/GResources/", "");
                if (key.Contains("."))
                {
                    key = key.Substring(0, key.LastIndexOf("."));
                    fileDic.Add(key, str);
                }
            }
        }
        return fileDic;
    }

    /// <summary>
    /// 获取文件的MD5值
    /// </summary>
    /// <param name="file"></param>
    /// <returns></returns>
    public static string GetFileMD5(string file)
    {
        try
        {
            FileStream fs = new FileStream(file, FileMode.Open);
            System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] retVal = md5.ComputeHash(fs);
            fs.Close();
            StringBuilder sb = new StringBuilder();
            foreach (var item in retVal)
            {
                sb.Append(item.ToString("x2"));
            }
            return sb.ToString();
        }
        catch(Exception e)
        {
            throw new Exception("GetFileMD5 fail,error:" + e);
        }
    }

    /// <summary>
    /// 获取lua代码的根路径
    /// </summary>
    /// <returns></returns>
    public static string GetLuaRootPath()
    {
        string path = "";
#if UNITY_EDITOR
        path = Application.dataPath + "/Lua/";
#else
        path = Application.persistentDataPath + "/Res/Lua/";
#endif
        //path = Application.streamingAssetsPath + "/Lua/";//Application.dataPath + "/Lua/";
        return path;
    }

    /// <summary>
    /// 获取lua代码的相对路径
    /// </summary>
    /// <param name="fileName"></param>
    /// <returns></returns>
    public static string GetLuaViewPath(string fileName)
    {
        string path = "";
        string view = "";
        string name = "";
        char[] strs = fileName.ToCharArray();
        view = fileName.Substring(strs.Length - 4);
        if (view != "View")
            return null;
        name = fileName.Substring(0, strs.Length - 4);
        name = name.Substring(0, 1) + name.Substring(1, name.Length - 1);
        Debug.Log("======name:" + name);
        //path = GetLuaRootPath() + "View/" + name + "/" + fileName + ".lua";
        path = "View/" + name + "/" + fileName;
        return path;
    }


    /// <summary>
    /// 获取lua proto的文件流
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public static byte[] GetLuaProtoBufferBytes(string name)
    {
        string path = GetLuaRootPath() + "Proto/" + name + ".pb.bytes";
        if(File.Exists(path))
        {
            FileStream fs = new FileStream(path, FileMode.Open);
            //获取文件大小
            long size = fs.Length;
            byte[] array = new byte[size];
            Debug.Log("size:" + size);
            return array;
        }
        return null;
    }

    /// <summary>
    /// 创建文件
    /// </summary>
    public static void CreateFile(byte[] bytes, string fileName)
    {
        
        string[] strs = fileName.Split('/');
        if(strs.Length > 0)
        {
            string dir = fileName.Substring(0, fileName.Length - strs[strs.Length - 1].Length);
            if (!Directory.Exists(dir))
            {
                Debug.LogError("path is not existe..:" + dir);
                return;
            }
            FileInfo fileInfo = new FileInfo(fileName);
            Stream stream = fileInfo.Create();
            stream.Write(bytes, 0, bytes.Length);
            stream.Close();
            stream.Dispose();
        }
    }


    public static void CreateLuaRes(string sourcePath, string savePath)
    {
        //string sourcePath = Application.dataPath + "/Lua";
        //string savePath = Application.streamingAssetsPath + "/Lua";
        if (!Directory.Exists(savePath))
        {
            Directory.CreateDirectory(savePath);
        }

        #region //拷贝labs文件夹到savePath下
        try
        {
            string[] labDirs = Directory.GetDirectories(sourcePath);//目录
            string[] labFiles = Directory.GetFiles(sourcePath);//文件
            if (labFiles.Length > 0)
            {
                foreach (string item in labFiles)
                {
                    string file = item.Replace("\\", "/");
                    if (file.EndsWith(".meta"))
                        continue;
                    string fileName = file.Substring(sourcePath.Length, file.Length - sourcePath.Length);
                    //File.Copy(file, savePath + fileName, true);
                    Read(file, savePath + fileName);
                }
            }

            if (labDirs.Length > 0)
            {
                for (int j = 0; j < labDirs.Length; j++)
                {
                    Directory.GetDirectories(sourcePath + "\\" + Path.GetFileName(labDirs[j]));

                    //递归调用
                    CreateLuaRes(sourcePath + "\\" + Path.GetFileName(labDirs[j]), savePath + "\\" + Path.GetFileName(labDirs[j]));
                }
            }
        }
        catch (Exception)
        {
           
        }
        #endregion
       
    }

    public static void CreateABByAES(string sourcePath, string savePath,string target = null)
    {
        if (!Directory.Exists(savePath))
        {
            Directory.CreateDirectory(savePath);
            if(target != null)
            {
                string mainAsset = sourcePath + "/" + target + "_Res";//+ "_Res.manifest";
                                                                      //string newMainAsset = savePath + "/" + ApplicationPlatform.GetRunPlatform();//+ ".manifest";

                string newMainAsset = Application.streamingAssetsPath + "/" + target + "/" + target;
                if (!File.Exists(newMainAsset))
                {
                    byte[] bytes = File.ReadAllBytes(mainAsset);
                    bytes = Encrypt(bytes, AppConfig.AB_KEY);
                    File.WriteAllBytes(newMainAsset, bytes);
                }
            }
        }

        #region //拷贝labs文件夹到savePath下
        try
        {
            string[] labDirs = Directory.GetDirectories(sourcePath);//目录
            string[] labFiles = Directory.GetFiles(sourcePath);//文件
            if (labFiles.Length > 0)
            {
                foreach (string item in labFiles)
                {
                    string file = item.Replace("\\", "/");
                    if (!file.EndsWith(".assetbundle"))
                        continue;
                    string fileName = file.Substring(sourcePath.Length, file.Length - sourcePath.Length);
                    string str = fileName.Split('.')[0] + ".assetbundle";
                    //File.Copy(file, savePath + fileName, true);
                    //Read(file, savePath + fileName);
                    byte[] bytes = File.ReadAllBytes(file);
                    bytes = Encrypt(bytes, AppConfig.AB_KEY);
                    File.WriteAllBytes(savePath + str, bytes);
                }
            }

            if (labDirs.Length > 0)
            {
                for (int j = 0; j < labDirs.Length; j++)
                {
                    Directory.GetDirectories(sourcePath + "\\" + Path.GetFileName(labDirs[j]));

                    //递归调用
                    CreateABByAES(sourcePath + "\\" + Path.GetFileName(labDirs[j]), savePath + "\\" + Path.GetFileName(labDirs[j]));
                }
            }
        }
        catch (Exception)
        {

        }
        #endregion

    }


    public static string ReadLua(string path)
    {
        StreamReader sr = new StreamReader(path, Encoding.UTF8);
        String line;
        StringBuilder sb = new StringBuilder();
        while ((line = sr.ReadLine()) != null)
        {
            sb.AppendLine(line.ToString());
        }
        return sb.ToString();
    }

    private static void Read(string path,string savePath)
    {
        StreamReader sr = new StreamReader(path, Encoding.UTF8);
        String line;
        StringBuilder sb = new StringBuilder();
        while ((line = sr.ReadLine()) != null)
        {
            sb.AppendLine(line.ToString());
        }
        string str = AESEncrypt(sb.ToString(), AppConfig.LUA_KEY);
        Write(savePath, str);
    }


    private static void Write(string path, string str)
    {
        FileStream fs = new FileStream(path, FileMode.Create);
        StreamWriter sw = new StreamWriter(fs);
        //开始写入
        sw.Write(str);
        //清空缓冲区
        sw.Flush();
        //关闭流
        sw.Close();
        fs.Close();
    }


    /// <summary>    
    /// AES加密(无向量)    
    /// </summary>    
    /// <param name="plainBytes">被加密的明文</param>    
    /// <param name="key">密钥</param>    
    /// <returns>密文</returns>    
    public static string AESEncrypt(String Data, String Key)
    {
        MemoryStream mStream = new MemoryStream();
        RijndaelManaged aes = new RijndaelManaged();

        byte[] plainBytes = Encoding.UTF8.GetBytes(Data);
        Byte[] bKey = new Byte[32];
        Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);

        aes.Mode = CipherMode.ECB;
        aes.Padding = PaddingMode.PKCS7;
        aes.KeySize = 128;
        //aes.Key = _key;    
        aes.Key = bKey;
        //aes.IV = _iV;    
        CryptoStream cryptoStream = new CryptoStream(mStream, aes.CreateEncryptor(), CryptoStreamMode.Write);
        try
        {
            cryptoStream.Write(plainBytes, 0, plainBytes.Length);
            cryptoStream.FlushFinalBlock();
            return Convert.ToBase64String(mStream.ToArray());
        }
        finally
        {
            cryptoStream.Close();
            mStream.Close();
            aes.Clear();
        }
    }



    /// <summary>    
    /// AES解密(无向量)    
    /// </summary>    
    /// <param name="encryptedBytes">被加密的明文</param>    
    /// <param name="key">密钥</param>    
    /// <returns>明文</returns>    
    public static string AESDecrypt(String Data, String Key)
    {
        Byte[] encryptedBytes = Convert.FromBase64String(Data);
        Byte[] bKey = new Byte[32];
        Array.Copy(Encoding.UTF8.GetBytes(Key.PadRight(bKey.Length)), bKey, bKey.Length);

        MemoryStream mStream = new MemoryStream(encryptedBytes);
        //mStream.Write( encryptedBytes, 0, encryptedBytes.Length );    
        //mStream.Seek( 0, SeekOrigin.Begin );    
        RijndaelManaged aes = new RijndaelManaged();
        aes.Mode = CipherMode.ECB;
        aes.Padding = PaddingMode.PKCS7;
        aes.KeySize = 128;
        aes.Key = bKey;
        //aes.IV = _iV;    
        CryptoStream cryptoStream = new CryptoStream(mStream, aes.CreateDecryptor(), CryptoStreamMode.Read);
        try
        {
            byte[] tmp = new byte[encryptedBytes.Length + 32];
            int len = cryptoStream.Read(tmp, 0, encryptedBytes.Length + 32);
            byte[] ret = new byte[len];
            Array.Copy(tmp, 0, ret, 0, len);
            return Encoding.UTF8.GetString(ret);
        }
        finally
        {
            cryptoStream.Close();
            mStream.Close();
            aes.Clear();
        }
    }

    /// <summary>
    /// 加密
    /// </summary>
    /// <param name="array">要加密的 byte[] 数组</param>
    /// <param name="key"></param>
    /// <returns></returns>
        public static byte[] Encrypt(byte[] array, string key)
    {
        key = FmtPassword(key);
        byte[] keyArray = Encoding.UTF8.GetBytes(key);

        RijndaelManaged rDel = new RijndaelManaged();
        rDel.Key = keyArray;
        rDel.Mode = CipherMode.ECB;
        rDel.Padding = PaddingMode.PKCS7;

        ICryptoTransform cTransform = rDel.CreateEncryptor();
        byte[] resultArray = cTransform.TransformFinalBlock(array, 0, array.Length);

        return resultArray;
    }


    /// <summary>
    /// 解密
    /// </summary>
    /// <param name="array">要解密的 byte[] 数组</param>
    /// <param name="key"></param>
    /// <returns></returns>
        public static byte[] Decrypt(byte[] array, string key)
    {
        key = FmtPassword(key);
        byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);

        RijndaelManaged rDel = new RijndaelManaged();
        rDel.Key = keyArray;
        rDel.Mode = CipherMode.ECB;
        rDel.Padding = PaddingMode.PKCS7;

        ICryptoTransform cTransform = rDel.CreateDecryptor();
        byte[] resultArray = cTransform.TransformFinalBlock(array, 0, array.Length);

        return resultArray;
    }


    /// <summary>
    /// 格式化密码
    /// </summary>
    /// <param name="s">要格式化的密码</param>
    /// <returns></returns>
    public static string FmtPassword(string s)
    {
        string password = s ?? "";

        //格式化密码
        if (password.Length < AESKeyLength)
        {
            //补足不够长的密码
            password = password + new string(AESFillChar, AESKeyLength - password.Length);
        }
        else if (password.Length > AESKeyLength)
        {
            //截取过长的密码
            password = password.Substring(0, AESKeyLength);
        }
        return password;
    }

    /// <summary>
    /// 获取ab资源配置文件
    /// </summary>
    /// <returns></returns>
    public static string GetAssetBundleManifsetPath()
    {
        string path = Application.streamingAssetsPath + "/" + ApplicationPlatform.GetRunPlatform() + "/" + ApplicationPlatform.GetRunPlatform();
        return path;
        
    }

    /// <summary>
    /// 检查热更路径是否有AB资源
    /// </summary>
    /// <param name="bundleName"></param>
    /// <returns></returns>
    public static bool CheckPersistentDataPathRes(string bundleName)
    {
        string path = Application.persistentDataPath + "/" + ApplicationPlatform.GetRunPlatform() + "/" + bundleName;
        if(File.Exists(path))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    /// <summary>
    /// 获取资源根路径
    /// </summary>
    /// <returns></returns>
    public static string GetResPath(string bundleName)
    {
        string path = "";
        if(CheckPersistentDataPathRes(bundleName))
        {
            path = Application.persistentDataPath + "/" + ApplicationPlatform.GetRunPlatform() + "/" + bundleName;
        }
        else
        {
            path = Application.streamingAssetsPath + "/" + ApplicationPlatform.GetRunPlatform() + "/" + bundleName;
        }
        return path;
    }

}
